/*******************************************************************************
  * 文件：MotorCtrl.c
  * 作者：djy
  * 版本：v1.0.0
  * 日期：2021-02-20
  * 说明：面板翻转电机驱动
*******************************************************************************/
#include "MotorCtrl.h"
#include "PWMCtrl.h"
#include "Hardware_ADC.h"
#include "Hardware_IO.h"

static StateMachine_ts sMotorSM;
/*******************************************************************************
  * 函数名：Motor_Coast
  * 功  能：电机滑行刹车
  * 参  数：无
  * 返回值：无
  * 说  明：INT1=0,INT2=0;
*******************************************************************************/
static void MotorCoast(void)
{
    // 电机滑行
    PWM_IN1Ctrl(U8_MOTOR_SPEED_DUTY_MIN);
    PWM_IN2Ctrl(U8_MOTOR_SPEED_DUTY_MIN);
}

/*******************************************************************************
  * 函数名：Motor_Brake
  * 功  能：电机制动
  * 参  数：无
  * 返回值：无
  * 说  明：INT1=1,INT2=1;
*******************************************************************************/
static void MotorBrake(void)
{
    // 电机制动
    PWM_IN1Ctrl(U8_MOTOR_SPEED_DUTY_MAX);
    PWM_IN2Ctrl(U8_MOTOR_SPEED_DUTY_MAX);
}

/*******************************************************************************
  * 函数名：Motor_Forward
  * 功  能：电机正转
  * 参  数：无
  * 返回值：无
  * 说  明：INT1=1,INT2=0;
*******************************************************************************/
static void MotorForward(void)
{
    // 电机前进
    PWM_IN1Ctrl(U8_MOTOR_SPEED_FORWARD_DUTY);
    PWM_IN2Ctrl(U8_MOTOR_SPEED_DUTY_MIN);
}

/*******************************************************************************
  * 函数名：Motor_Reverse
  * 功  能：电机翻转
  * 参  数：无
  * 返回值：无
  * 说  明：INT1=0,INT2=1;
*******************************************************************************/
static void MotorReverse(void)
{
    // 电机后退
    PWM_IN1Ctrl(U8_MOTOR_SPEED_DUTY_MIN);
    PWM_IN2Ctrl(U8_MOTOR_SPEED_REVERSE_DUTY);
}

/*******************************************************************************
  * 函数名：Motor_ClosedHandler
  * 功  能：升降面板完全关闭处理
  * 参  数：无
  * 返回值：无
  * 说  明：1.第一秒电机制动，一秒后切换为滑行；2.定时检测是否手动抬起
*******************************************************************************/
static U32 Motor_ClosedHandler(void)
{
    // 判断重试次数
    if(StateMachine_GetRetryCount(&sMotorSM) < 100)
    {
        // 第一秒内，电机制动
        MotorBrake();
    }
    else
    {
        // 一秒后，电机滑行
        MotorCoast();

        // 检测限位开关
        if(Hardware_CloseStopCheck() == HIGH && Hardware_OpenStopCheck() == HIGH)
        {
            // 若面板完全关闭时，手动将面板打开，切换至打开时停止状态
            Motor_ChangeState(eMOTOR_OPENING_PAUSE);

            // 提前退出
            return STATE_CTRL_HOLD;
        }
    }

    // 重试此状态
    return STATE_CTRL_RETRY;
}

/*******************************************************************************
  * 函数名：Motor_OpenedHandler
  * 功  能：升降面板完全打开处理
  * 参  数：无
  * 返回值：无
  * 说  明：1.第一秒电机制动，一秒后切换为滑行；2.定时检测是否手动关闭
*******************************************************************************/
static U32 Motor_OpenedHandler(void)
{
    // 判断重试次数
    if(StateMachine_GetRetryCount(&sMotorSM) < 100)
    {
        // 第一秒内，电机制动
        MotorBrake();
    }
    else
    {
        // 一秒后，电机滑行
        MotorCoast();

        // 检测限位开关
        if(Hardware_CloseStopCheck() == HIGH && Hardware_OpenStopCheck() == HIGH)
        {
            // 若面板完全打开时，手动将面板关闭，切换至关闭时停止状态
            Motor_ChangeState(eMOTOR_CLOSING_PAUSE);

            // 提前退出
            return STATE_CTRL_HOLD;
        }
    }

    // 重试此状态
    return STATE_CTRL_RETRY;
}

/*******************************************************************************
  * 函数名：Motor_ClosingHandler
  * 功  能：升降面板正在关闭处理
  * 参  数：无
  * 返回值：无
  * 说  明：1.定时检测是否堵转；2.定时检测是否完成
*******************************************************************************/
static U32 Motor_ClosingHandler(void)
{
    static U8 u8BlockTick;

    // 判断重试次数
    if(StateMachine_GetRetryCount(&sMotorSM) == 0)
    {
        // 清空堵转计时
        u8BlockTick = 0;
        
        // 电机反转
        MotorReverse();
    }
    else
    {
        // 堵转检测
        if(Hardware_GetMotorBlock() >= U16_MOTOR_REVERSE_BLOCK_ADC)
        {
            // 堵转计时
            u8BlockTick++;
            
            // 堵转超时
            if(u8BlockTick >= U8_MOTOR_BLOCK_OVER_TIME)
            {
                // 清零计时
                u8BlockTick = 0;
                
                // 切换至关闭时停止
                Motor_ChangeState(eMOTOR_CLOSING_PAUSE);

                // 提前退出
                return STATE_CTRL_HOLD;
            }
        }
        else
        {
            // 清空堵转计时
            u8BlockTick = 0;
        }

        // 限位开关检测
        if(Hardware_CloseStopCheck() == LOW)
        {
            // 后限位开关闭合，切换至完全关闭
            Motor_ChangeState(eMOTOR_CLOSED);
            
            // 提前退出
            return STATE_CTRL_HOLD;
        }
    }
    
    // 重试此状态
    return STATE_CTRL_RETRY;
}

/*******************************************************************************
  * 函数名：Motor_OpeningHandler
  * 功  能：升降面板正在打开处理
  * 参  数：无
  * 返回值：无
  * 说  明：1.定时检测是否堵转；2.定时检测是否完全打开
*******************************************************************************/
static U32 Motor_OpeningHandler(void)
{
    static U8 u8BlockTick;

    // 判断重试次数
    if(StateMachine_GetRetryCount(&sMotorSM) == 0)
    {
        // 清空堵转计时
        u8BlockTick = 0;
        
        // 电机正转
        MotorForward();
    }
    else
    {
        // 堵转检测
        if(Hardware_GetMotorBlock() >= U16_MOTOR_FORWARD_BLOCK_ADC)
        {
            // 堵转计时
            u8BlockTick++;
            
            // 堵转超时
            if(u8BlockTick >= U8_MOTOR_BLOCK_OVER_TIME)
            {
                // 清零计时
                u8BlockTick = 0;
                
                // 切换至关闭时停止
                Motor_ChangeState(eMOTOR_OPENING_PAUSE);

                // 提前退出
                return STATE_CTRL_HOLD;
            }
        }
        else
        {
            // 清空堵转计时
            u8BlockTick = 0;
        }

        // 限位开关检测
        if(Hardware_OpenStopCheck() == LOW)
        {
            // 前限位开关闭合，切换至完全打开
            Motor_ChangeState(eMOTOR_OPENED);
            
            // 提前退出
            return STATE_CTRL_HOLD;
        }
    }
    
    // 重试此状态
    return STATE_CTRL_RETRY;
}

/*******************************************************************************
  * 函数名：Motor_ClosingPauseHandler
  * 功  能：升降面板关闭时暂停处理
  * 参  数：无
  * 返回值：无
  * 说  明：1.电机滑行；2.定时检测限位开关状态，切换至完全关闭或开启
*******************************************************************************/
static U32 Motor_ClosingPauseHandler(void)
{
    // 电机滑行
    MotorCoast();

    // 检测升降面板是否被手动关闭
    if(Hardware_CloseStopCheck() == LOW)
    {
        // 切换为完全关闭
         Motor_ChangeState(eMOTOR_CLOSED);
        
        // 提前退出
        return STATE_CTRL_HOLD;
    }
    // 检测升降面板是否被手动开启
    else if(Hardware_OpenStopCheck() == LOW)
    {
        // 切换为完全开启
        Motor_ChangeState(eMOTOR_OPENED);
        
        // 提前退出
        return STATE_CTRL_HOLD;
    }
    else
    {
        // 重试此状态
        return STATE_CTRL_RETRY;
    }
}

/*******************************************************************************
  * 函数名：Motor_OpeningPauseHandler
  * 功  能：升降面板开启时暂停处理
  * 参  数：无
  * 返回值：无
  * 说  明：1.电机滑行；2.定时检测限位开关状态，切换至完全关闭或开启
*******************************************************************************/
static U32 Motor_OpeningPauseHandler(void)
{
    // 电机滑行
    MotorCoast();

    // 检测升降面板是否被手动关闭
    if(Hardware_CloseStopCheck() == LOW)
    {
        // 切换为完全关闭
         Motor_ChangeState(eMOTOR_CLOSED);
        
        // 提前退出
        return STATE_CTRL_HOLD;
    }
    // 检测升降面板是否被手动开启
    else if(Hardware_OpenStopCheck() == LOW)
    {
        // 切换为完全开启
        Motor_ChangeState(eMOTOR_OPENED);
        
        // 提前退出
        return STATE_CTRL_HOLD;
    }
    else
    {
        // 重试此状态
        return STATE_CTRL_RETRY;
    }
}

// 状态表  按照业务逻辑划分状态机
static const StateMachineOps_ts asSMOpts[] =
{
    STATE_MACHINE_STATE(eMOTOR_CLOSED,          eMOTOR_CLOSED,     10,  Motor_ClosedHandler          ),
    STATE_MACHINE_STATE(eMOTOR_OPENED,          eMOTOR_OPENED,     10,  Motor_OpenedHandler          ),

    STATE_MACHINE_STATE(eMOTOR_CLOSING,         eMOTOR_CLOSED,     10,  Motor_ClosingHandler         ),
    STATE_MACHINE_STATE(eMOTOR_OPENING,         eMOTOR_OPENED,     10,  Motor_OpeningHandler         ),

    STATE_MACHINE_STATE(eMOTOR_CLOSING_PAUSE,   eMOTOR_OPENING,    10,  Motor_ClosingPauseHandler    ),
    STATE_MACHINE_STATE(eMOTOR_OPENING_PAUSE,   eMOTOR_CLOSING,    10,  Motor_OpeningPauseHandler    ),
};

/*******************************************************************************
  * 函数名：Motor_GetState
  * 功  能：获取翻转电机状态
  * 参  数：无
  * 返回值：eMotorState：电机运行状态
  * 说  明：无
*******************************************************************************/
U8 Motor_GetState(void)
{
    return StateMachine_GetCurState(&sMotorSM);
}

/*******************************************************************************
  * 函数名：Motor_ChangeState
  * 功  能：切换翻转电机状态
  * 参  数：eMotorState：电机运行状态
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void Motor_ChangeState(MotorState_te eMotorState)
{
    StateMachine_Change(&sMotorSM,eMotorState);
}

/*******************************************************************************
  * 函数名：Motor_Init
  * 功  能：面板翻转电机驱动初始化
  * 参  数：无
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void Motor_Init(void)
{
    // 初始化状态机
    StateMchine_Init(&sMotorSM,
                    "Motor Ctrl SM", 
                    asSMOpts, 
                    ARRAY_SIZE(asSMOpts));

    // 检测后限位开关
    if(LOW == Hardware_CloseStopCheck())
    {
        // 后限位开关闭合，即完全关闭状态
        Motor_ChangeState(eMOTOR_CLOSED);
    }
    // 检测前限位开关
    else if(LOW == Hardware_OpenStopCheck())
    {
        // 前限位开关闭合，即完全打开状态
        Motor_ChangeState(eMOTOR_OPENED);
    }
    else 
    {
        // 限位开关都不闭合，缺省为关闭时停止
        Motor_ChangeState(eMOTOR_CLOSING_PAUSE);
    }
}

